﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using XMLGener.Utils;
using XMLGener.Data;

namespace XMLGener.GUI
{
    /// <summary>
    /// This form shows generating status. 
    /// </summary>
    public partial class ProcessForm : Form
    {
        delegate void AddLogCallBack(XLogMessage message);

        /// <summary>
        /// Constructor of process form.
        /// </summary>
        public ProcessForm(string sourceFileName)
        {
            InitializeComponent();
            customInitialization(sourceFileName);
            
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }




        private XLogger logger = null;
        private XMLGenerDocument doc;

        private void customInitialization(string sourceFileName)
        {
            this.logger = new XLogger();
            this.logger.errorEvent += this.logHandler;
            this.logger.logEvent += this.logHandler;

            sourceFile = sourceFileName;
            

        }

        private void logHandler(XLogMessage message)
        {
            /*if (lf == null)
            {
                lf = new LogForm();
                lf.addMessage(message);
            }
            lf.Show();*/
            if (this.logList.InvokeRequired)
            {
                AddLogCallBack d = new AddLogCallBack(logHandler);
                this.Invoke(d, new object[] { message });

            }
            else
            {
                this.logList.Items.Add(message);
            }
        }

       

        private string sourceFile;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessForm_Load(object sender, EventArgs e)
        {
            this.backGroundGenerating.RunWorkerAsync();
            this.stateTimer.Enabled = true;
            
        }


        private static decimal ONE_YEAR_IN_TICKS = 10000000m * 60m * 60m * 24m * 365m;
       
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (this.doc == null || this.doc.totalSum < 1)
                return;
            
            decimal current = this.doc.generatedElements;
            decimal promile = current * 1000 / this.doc.totalSum;
            if (promile > 1000) promile = 1000;
            if (backGroundGenerating.CancellationPending)
                this.doc.stopGenerating = true;
            this.progressBar1.Value = Convert.ToInt32(promile);
            this.lgenerated.Text = Convert.ToString(current);

            TimeSpan ts = tim.Elapsed;

            decimal d =0;
            if (current >0)
                d = (Convert.ToDecimal(ts.Ticks) * (this.doc.totalSum - current)) / (current);
            
            // Format and display the TimeSpan value.
            lbSpentTime.Text= String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
            if (d > ONE_YEAR_IN_TICKS)
            {
                lbEstimated.Text = "more than one year";
            }
            else
            {
                TimeSpan est = new TimeSpan(Convert.ToInt64(d));
                if (est.Days > 0)
                    lbEstimated.Text = String.Format("{4} days {0:00}:{1:00}:{2:00}.{3:00}",
                        est.Hours, est.Minutes, est.Seconds, est.Milliseconds / 10, est.Days);
                else
                    lbEstimated.Text = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                        est.Hours, est.Minutes, est.Seconds, est.Milliseconds / 10);
            }


        }
        private Stopwatch tim = new Stopwatch();
        private bool generatingFinished = false;
        private void backgroundWorker1_DoWork_1(object sender, DoWorkEventArgs e)
        {

            this.doc = new XMLGenerDocument(this.logger);
            this.doc.LoadFromFile(sourceFile);
            if (!(this.doc.check()))
            {
                generatingFinished = true;
                return;
            }
            this.doc.startGeneratingEvent += this.startTimer;
            this.doc.generate(true);
            this.doc.startGeneratingEvent -= this.startTimer;
            // Get the elapsed time as a TimeSpan value.
            tim.Stop();
            TimeSpan ts = tim.Elapsed;

            // Format and display the TimeSpan value.
            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                ts.Hours, ts.Minutes, ts.Seconds,
                ts.Milliseconds / 10);
            this.doc.logger.addLog("Generator", "Generated in time: " + elapsedTime);
            generatingFinished = true;
 
        }
        private void startTimer(XLogMessage message)
        {
            tim.Start();
        }
       
        private void btStop_Click(object sender, EventArgs e)
        {
            if (generatingFinished)
            {
                this.Close();
            }else
            this.backGroundGenerating.CancelAsync();
        }

        private void backGroundGenerating_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                // There was an error during generating
                this.doc.logger.addLog("Generator", String.Format("An error occurred: {0}", e.Error.Message));
            }
            else if (!e.Cancelled )
            {
                // The generating done successfully.
                btStop.Text = "Close";
                
            }

        }

        private void ProcessForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.logger.errorEvent -= this.logHandler;
            this.logger.logEvent -= this.logHandler;
            this.doc.stopGenerating = true;
        }

      

       
    }
}
